/*
 *  levelUpGame - PngSequencePlayer.cpp
 *  Copyright 2011 W. Reckman. All rights reserved.
 */
#include "ofImage.h"
#include "PngSequencePlayer.h"


const int PngSequencePlayer::MAX_IMAGE_FILES = 125;
const int PngSequencePlayer::DEFAULT_FRAMERATE = 25;

PngSequencePlayer::PngSequencePlayer()
: frameRate( DEFAULT_FRAMERATE ), frameDuration( 1.0f / frameRate ), mode( PSP_LOOP_FORWARD ), playing( false ),
  pingpongForward( true ), currentFrame( 0 ), lastElapsedTime( 0.0f )
{}

PngSequencePlayer::~PngSequencePlayer() {
	clear();
}

bool PngSequencePlayer::loadSequence( const string& path, const string& prefix ) {
	clear();
	
	dirList.reset();
	dirList.allowExt( "png" );
	int numFiles = dirList.listDir( path );
	
	if ( numFiles == 0 ) {
		ofLog( OF_LOG_ERROR, "(PngSequencePlayer.cpp) could not load sequence because no .png files were found (path='%s')", path.c_str() );
		return false;
	}
	
	if ( numFiles <= MAX_IMAGE_FILES ) {
		int highestIndex = -1;
		
		seqImages.resize( numFiles );
		for ( int i = 0; i < numFiles; ++i ) {
			string imgName = dirList.getName( i );
			string imgPath = dirList.getPath( i );
			
			if ( imgName.find( prefix ) != 0 ) {
				ofLog( OF_LOG_WARNING, "(PngSequencePlayer.cpp) ignoring file '%s' because it does not start with the correct prefix ('%s')",
							imgPath.c_str(), prefix.c_str() );
				continue;
			}
			
			int idx = ofToInt( imgName.substr( prefix.length(), imgName.rfind( '.' ) - prefix.length() ) );
			if ( idx > highestIndex ) highestIndex = idx;
			
			if ( idx >= 1 && idx <= numFiles ) {
				ofImage* img = new ofImage();
				bool rv = img->loadImage( imgPath );
				if (rv ) {
					seqImages[idx - 1] = img;
				} else {
					ofLog( OF_LOG_ERROR, "(PngSequencePlayer.cpp) could not load image file '%s'", imgPath.c_str() );
					delete img;
				}
			} else {
				ofLog( OF_LOG_WARNING, "(PngSequencePlayer.cpp) ignoring file '%s' because its index is out of range (%i, range=%i - %i)",
							imgPath.c_str(), idx, 1, numFiles + 1 );
			}
		}
		
		if ( highestIndex < seqImages.size() - 1 ) {
			seqImages.resize( highestIndex );
		}
		
		if ( seqImages.size() > 0 ) size.set( seqImages[0]->getWidth(), seqImages[0]->getHeight() );
		
		ofLog( OF_LOG_NOTICE, "(PngSequencePlayer.cpp) loaded PNG sequence  from '%s' with %i frames",
					path.c_str(), seqImages.size() );
		
		return true;
	} else {
		ofLog( OF_LOG_ERROR, "(PngSequencePlayer.cpp) image sequence not loaded because it contains too many files (%i > %i, path='%s', prefix='%s')",
					numFiles, MAX_IMAGE_FILES, path.c_str(), prefix.c_str() );
		return false;
	}
}

void PngSequencePlayer::clear() {
	currentFrame = 0;
	
	vec_ofImageP::iterator it;
	for ( it = seqImages.begin(); it != seqImages.end(); ++it ) {
		ofImage* img = *it;
		delete img;
		seqImages.erase( it );
	}
}

void PngSequencePlayer::play() { playing = true; }
void PngSequencePlayer::stop() { playing = false; }
void PngSequencePlayer::rewind() { currentFrame = 0; }

void PngSequencePlayer::update() {
	if ( ! playing ) return;
	
	float elapsed = ofGetElapsedTimef() - lastElapsedTime;
	
	if ( elapsed < frameDuration ) return;
	
	lastElapsedTime += frameDuration;
	//lastElapsedTime += elapsed;
	
	int lastFrameIdx = seqImages.size() - 1;
	switch ( mode ) {
		case PSP_FORWARD: case PSP_LOOP_FORWARD:
			currentFrame++;
			if ( currentFrame > lastFrameIdx ) {
				currentFrame = 0;
				if ( mode != PSP_LOOP_FORWARD ) playing = false;
			}
			break;
		case PSP_BACKWARD: case PSP_LOOP_BACKWARD:
			currentFrame--;
			if ( currentFrame < 0 ) {
				currentFrame = lastFrameIdx;
				if ( mode != PSP_LOOP_BACKWARD ) playing = false;
			}
			break;
		case PSP_LOOP_PINGPONG:
			if ( pingpongForward ) {
				currentFrame++;
				if ( currentFrame >= lastFrameIdx ) {
					pingpongForward = false;
				}
			} else {
				currentFrame--;
				if ( currentFrame <= 0 ) {
					pingpongForward = true;
				}
			}
			break;
	}
}

void PngSequencePlayer::draw( int x, int y ) const {
	if ( seqImages.size() > 0 && seqImages[currentFrame] != 0 ) {
		
		seqImages[currentFrame]->draw( x, y );
	}
}

void PngSequencePlayer::draw( int x, int y, int w, int h ) const {
	if ( seqImages.size() > 0 && seqImages[currentFrame] != 0 ) {
		seqImages[currentFrame]->draw( x, y, w, h );
	}
}

void PngSequencePlayer::setFrameRate( int frameRate_ ) { frameRate = frameRate_; frameDuration = 1.0f / frameRate; }
void PngSequencePlayer::setMode( PNG_SEQ_PLAY_MODE mode_ ) { mode = mode_; }

//NOTE: size returned is that of the first frame (they should all be of equal size though)
const ofPoint& PngSequencePlayer::getSize() const { return size; }

bool PngSequencePlayer::isPlaying() const { return playing; }
int PngSequencePlayer::getFrameRate() const { return frameRate; }
int PngSequencePlayer::getNumFrames() const { return seqImages.size(); }
int PngSequencePlayer::getCurrentFrame() const { return currentFrame; }
PngSequencePlayer::PNG_SEQ_PLAY_MODE PngSequencePlayer::getMode() const { return mode; }
